const jwt = require("jsonwebtoken");
const { v4: uuidv4 } = require("uuid");

const client = require("../config/Redis");

// 引入配置中心
const config = require("../config");

// 从配置中解构出需要的值
const { JWT_SECRET, TOKEN_CONFIG } = config;

// --- Token 操作函数 ---
/**
 * 生成 Access Token 并存入 Redis 状态
 * * 机制：生成一个唯一的 JTI，JTI作为Token的身份标识，并将其存入Redis。
 * * @param {number|string} userId - 用户 ID
 * @param {number|string} roleId - 用户角色 ID
 * @returns {Promise<string>} - Access Token 字符串
 */
async function generateToken(userId, roleId) {
  const tokenId = uuidv4(); // Token ID (JTI)
  // 载荷中只包含 user_id, role_id 和 tokenId (JTI)
  const payload = {
    user_id: userId,
    role_id: roleId,
    jti: tokenId,
  };

  const accessToken = jwt.sign(payload, JWT_SECRET);

  // 将 Token 状态存入 Redis，并设置过期时间
  const redisKey = TOKEN_CONFIG.TOKEN_PREFIX + tokenId;

  // ioredis SET 命令: SET key value EX seconds
  await client.set(
    redisKey,
    String(userId),
    "EX",
    TOKEN_CONFIG.EXPIRATION_SECONDS
  );

  console.log(
    `[Token] Generated for User: ${userId}, Token ID: ${tokenId.substring(
      0,
      8
    )}...`
  );
  return accessToken;
}

/**
 * 校验 Token，同时实现续期
 * * 机制：双重验证 (签名 + Redis 状态)，验证成功后重置 Redis TTL。
 * * @param {string} token - Access Token 字符串
 * @returns {Promise<object>} - { valid: boolean, userId?: string, roleId?: string, tokenId?: string, message?: string }
 */
async function verifyToken(token) {
  let payload;
  try {
    // 1. 验证 JWT 签名，检查格式和过期时间
    payload = jwt.verify(token, JWT_SECRET);
  } catch (error) {
    // JWT 签名或格式验证失败
    return { valid: false, message: "无效的令牌签命或格式。" };
  }

  const { user_id: userId, role_id: roleId, jti: tokenId } = payload;
  const redisKey = TOKEN_CONFIG.TOKEN_PREFIX + tokenId;

  // 2. 检查 Redis 中是否存在对应的 Key (实时状态检查)
  // ioredis GET 命令
  const exists = await client.get(redisKey);

  if (!exists) {
    // Redis 中不存在，说明 Token 已过期或已被主动删除 (logout)
    return { valid: false, message: "令牌已过期或已注销。" };
  }

  // 3. 续期 (重置 Redis Key 的过期时间)
  // ioredis EXPIRE 命令
  await client.expire(redisKey, TOKEN_CONFIG.EXPIRATION_SECONDS);
  console.log(
    `[Token] Verified and Renewed for Token ID: ${tokenId.substring(0, 8)}...`
  );

  // 4. Token 有效
  return {
    valid: true,
    userId: userId,
    roleId: roleId,
    tokenId: tokenId,
  };
}

/**
 * 主动过期/退出
 * * 机制：直接删除 Redis 中的 JTI 键，实现 Token 立即作废。
 * * @param {string} tokenId - 要吊销的 Token ID (JTI)
 * @returns {Promise<boolean>}
 */
async function revokeToken(tokenId) {
  if (!tokenId) return false;
  const redisKey = TOKEN_CONFIG.TOKEN_PREFIX + tokenId;

  // ioredis DEL 命令
  const result = await client.del(redisKey);
  console.log(`[Token] Revoked Token ID: ${tokenId.substring(0, 8)}...`);

  // DEL 命令返回删除的 key 数量
  return result > 0;
}

module.exports = { generateToken, verifyToken, revokeToken };
